/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Copyright (C) 2016-2018, LomboTech Co.Ltd.
 * Author: lomboswer <lomboswer@lombotech.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#ifndef __LOMBO_CLK_CSP_H
#define __LOMBO_CLK_CSP_H

#include <mach/csp.h>
#include <mach/common.h>

#define MASK(width)	((1 << (width)) - 1)

/* get factor, prev/post div from reg value */
#define GET(val, shift, width)	(((val) >> (shift)) & MASK(width))
#define FAC_N(val)	GET(val, pll->fac_shift[FAC], pll->fac_width[FAC])
#define PREV_DIV(val) (1 + GET(val, pll->fac_shift[PREV], pll->fac_width[PREV]))
#define POST_DIV(val) (1 + GET(val, pll->fac_shift[POST], pll->fac_width[POST]))

#define AD_FAC_N(val)	GET(val, adpll->fac_shift[AD_FAC],		\
				adpll->fac_width[AD_FAC])
#define AD_POST_DIV(val) (1 + GET(val, adpll->fac_shift[AD_POST],	\
				adpll->fac_width[AD_POST]))

#define CLR_BITS(reg, shift, width)	((reg) & ~(MASK(width) << shift))
#define FORM_BITS(val, shift, width)	((val & MASK(width)) << shift)
#define SET(reg, val, shift, width)	(CLR_BITS(reg, shift, width) |	\
						FORM_BITS(val, shift, width))
/* set factor, prev/post div from reg value */
#define SET_FAC_N(reg, val)	SET(reg, val, pll->fac_shift[FAC],	\
					pll->fac_width[FAC])
#define SET_PREV_DIV(reg, val)	SET(reg, val, pll->fac_shift[PREV],	\
					pll->fac_width[PREV])
#define SET_POST_DIV(reg, val)	SET(reg, val, pll->fac_shift[POST],	\
					pll->fac_width[POST])

/* set N Frac */
#define SET_N_FRAC(reg, val)	SET(reg, val, 0, 18)

/* set factor, post div from reg value */
#define AD_SET_FAC_N(reg, val)	SET(reg, val, adpll->fac_shift[AD_FAC],	\
					adpll->fac_width[AD_FAC])
#define AD_SET_POST_DIV(reg, val) SET(reg, val, adpll->fac_shift[AD_POST],\
					adpll->fac_width[AD_POST])

/* PLL Tune1 Register */
typedef union {
	u32 val;
	struct {
	u32 period:12;
	u32 rsvd0:4;
	u32 amplitude:12;
	u32 rsvd1:4;
	} bits;
} reg_prcm_pll_tune1_t;

/* PLL Tune2 Register */
typedef union {
	u32 val;
	struct {
	u32 en:1;
	u32 rsvd0:15;
	u32 step:16;
	} bits;
} reg_prcm_pll_tune2_t;

/*
 * pll_linear_name:array of clk names that support linear frequency division
 * pll_spread_name:array of clk names that support spread spectrun
 * pll_linear_counts:number of clk that support linear frequency division
 * pll_spread_counts:number of clk that support spread spectrun
 */
extern const char *pll_linear_name[];
extern const char *pll_spread_name[];
extern const int pll_linear_counts;
extern const int pll_spread_counts;

extern const char *clk_to_en[];
extern const int clk_to_en_counts;

bool is_ignore_unused_clk(const char *name);
void csp_enable_spread_during_linear(int enable, void __iomem *addr);
void csp_set_linear_adjust_freq_step(u32 step, void __iomem *addr);
void csp_set_spread_para(u32 amplitude, u32 period, void __iomem *addr);
int __get_fac_max(const char *name, int pre_div);

#endif /* __LOMBO_CLK_CSP_H */
